package cn.cdeden.system.listener;

import cn.cdeden.system.domain.SysDept;
import cn.cdeden.system.domain.bo.SysDeptBo;
import cn.cdeden.system.domain.vo.SysDeptVo;
import cn.cdeden.system.domain.vo.SysUserImportNewVo;
import cn.cdeden.system.mapper.SysDeptMapper;
import cn.cdeden.system.service.ISysDeptService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.http.HtmlUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import cn.cdeden.common.core.exception.ServiceException;
import cn.cdeden.common.core.utils.SpringUtils;
import cn.cdeden.common.core.utils.StreamUtils;
import cn.cdeden.common.core.utils.ValidatorUtils;
import cn.cdeden.common.excel.core.ExcelListener;
import cn.cdeden.common.excel.core.ExcelResult;
import cn.cdeden.common.satoken.utils.LoginHelper;
import cn.cdeden.system.domain.bo.SysUserBo;
import cn.cdeden.system.domain.vo.SysUserVo;
import cn.cdeden.system.service.ISysConfigService;
import cn.cdeden.system.service.ISysUserService;

import java.util.List;

/**
 * 系统用户自定义导入
 *
 * @author Lion Li
 */
@Slf4j
public class SysUserImportListener extends AnalysisEventListener<SysUserImportNewVo> implements ExcelListener<SysUserImportNewVo> {

    private final ISysUserService userService;

    private final ISysDeptService deptService;

    private final SysDeptMapper deptMapper;

    private final String password;

    private final Boolean isUpdateSupport;

    private final Long operUserId;

    private int successNum = 0;
    private int failureNum = 0;
    private final StringBuilder successMsg = new StringBuilder();
    private final StringBuilder failureMsg = new StringBuilder();

    public SysUserImportListener(Boolean isUpdateSupport) {
        String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword");
        this.userService = SpringUtils.getBean(ISysUserService.class);
        this.deptService = SpringUtils.getBean(ISysDeptService.class);
        this.deptMapper = SpringUtils.getBean(SysDeptMapper.class);
        this.password = BCrypt.hashpw(initPassword);
        this.isUpdateSupport = isUpdateSupport;
        this.operUserId = LoginHelper.getUserId();
    }

    @Override
    public void invoke(SysUserImportNewVo userVo, AnalysisContext context) {
        SysUserVo sysUser = this.userService.selectUserByUserName(userVo.getUserName());
        try {
            if (ObjectUtil.isNotNull(sysUser)) {
                // 用户已存在的处理
                if (isUpdateSupport) {
                    updateUser(sysUser, userVo); // 执行更新逻辑
                } else {
                    recordFailure(sysUser.getUserName(), "已存在，未启用更新功能"); // 记录失败信息
                }
            } else {
                createUser(userVo); // 执行创建逻辑
            }
        } catch (Exception e) {
            handleImportError(userVo, e); // 异常处理
        }
    }

    /**
     * 创建用户
     */
    private void createUser(SysUserImportNewVo userVo) {
        Long deptId = handleDept(userVo.getDeptName());
        SysUserBo user = buildSysUser(userVo, deptId);
        user.setCreateBy(operUserId);
        userService.insertUser(user);

        successNum++;
        successMsg.append("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" 导入成功");
    }

    /**
     * 更新用户
     */
    private void updateUser(SysUserVo sysUser, SysUserImportNewVo userVo) {
        Long deptId = handleDept(userVo.getDeptName());
        SysUserBo user = buildSysUser(userVo, deptId);
        user.setUserId(sysUser.getUserId());
        user.setUpdateBy(operUserId);

        userService.checkUserAllowed(user.getUserId());
        userService.checkUserDataScope(user.getUserId());
        userService.updateUser(user);

        successNum++;
        successMsg.append("<br/>").append(successNum).append("、账号 ").append(user.getUserName()).append(" 更新成功");
    }

    /**
     * 记录失败原因
     */
    private void recordFailure(String userName, String reason) {
        failureNum++;
        failureMsg.append("<br/>").append(failureNum).append("、账号 ").append(userName).append(" ").append(reason);
    }

    /**
     * 部门处理：检查部门是否存在，不存在则递归创建
     */
    private Long handleDept(String deptName) {
        if (ObjectUtil.isEmpty(deptName)) {
            return null; // 无部门信息
        }
        String[] split = deptName.split("/");
        Long parentDeptId = 100L; // 一级部门的 parentId
        Long deptId = null;

        for (String currentDeptName : split) {
            currentDeptName = currentDeptName.trim(); // 标准化部门名称
            SysDept sysDept = deptMapper.selectOne(new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getDeptName, currentDeptName)
                .eq(SysDept::getParentId, parentDeptId));

            if (ObjectUtil.isNull(sysDept)) {
                // 如果当前部门不存在，创建新部门
                SysDeptBo dept = new SysDeptBo();
                dept.setDeptName(currentDeptName);
                dept.setParentId(parentDeptId);
                dept.setOrderNum(0);
                deptId = deptService.insertDeptReturnId(dept);
            } else {
                deptId = sysDept.getDeptId();
            }
            parentDeptId = deptId;
        }
        return deptId;
    }

    /**
     * 构建 SysUserBo 对象
     */
    private SysUserBo buildSysUser(SysUserImportNewVo userVo, Long deptId) {
        SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class);
        user.setDeptId(deptId);
        user.setStatus("0");
        user.setPassword(password);
        user.setRoleIds(new Long[]{5L}); // 默认角色ID，建议从配置读取
        ValidatorUtils.validate(user);
        return user;
    }

    /**
     * 错误处理
     */
    private void handleImportError(SysUserImportNewVo userVo, Exception e) {
        failureNum++;
        String msg = "<br/>" + failureNum + "、账号 " + HtmlUtil.cleanHtmlTag(userVo.getUserName()) + " 导入失败：";
        String message = e instanceof ConstraintViolationException cvException
            ? StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", ")
            : e.getMessage();

        failureMsg.append(msg).append(message);
        log.error(msg, e);
    }


    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {

    }

    @Override
    public ExcelResult<SysUserImportNewVo> getExcelResult() {
        return new ExcelResult<SysUserImportNewVo>() {

            @Override
            public String getAnalysis() {
                if (failureNum > 0) {
                    failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
                    throw new ServiceException(failureMsg.toString());
                } else {
                    successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
                }
                return successMsg.toString();
            }

            @Override
            public List<SysUserImportNewVo> getList() {
                return null;
            }

            @Override
            public List<String> getErrorList() {
                return null;
            }
        };
    }
}
